package c2.cross.business.championrace.sub;

import c2.cross.business.base.CrossSubModule;
import c2.cross.business.championrace.ChampionRaceModule;
import cate.common.table.d.GDChampionRace;
import cate.common.table.d.GDFight;
import cate.common.util.GameResult;
import cate.game.framework.common.compress.CompressedContent;
import cate.game.framework.common.compress.PlaySideCompressHelper;
import cate.game.play.part.FightSide;
import cate.game.play.part.PlaySide;
import cate.game.play.proce.play.PlayPO;
import cate.game.play.vo.PlayVO;
import cate.game.play.vo.ReplayUtils;
import cate.game.pvp.championrace.ChampionRaceFTC;
import cate.game.pvp.championrace.data.ChampionRacePs;
import cate.game.pvp.championrace.data.ChampionRaceRecord;
import cate.game.pvp.championrace.ChampionRaceSpecUtils;
import cate.game.pvp.championrace.data.ChampionRaceVideo;
import cp.solution.manage.api.open.replay.ReplaySaveReq;
import easy.java.practice.errorcode.EcResult;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;

@Slf4j
public class ChampionRaceFightModule extends CrossSubModule<ChampionRaceModule> {
    public GameResult<Long> startFight(ChampionRaceRecord record, ChampionRacePs psA, ChampionRacePs psB) {
        GameResult<Long> r = new GameResult<>();
        PlaySide sideA = null, sideB = null;
        if (Objects.nonNull(psA)) {
            record.setPsA(psA.getCpsList().size() - 1);
            CompressedContent cc = psA.getCpsList().get(record.getPsA());
            EcResult<PlaySide> uncompressEc = PlaySideCompressHelper.uncompressEc(cc);
            if (!uncompressEc.ok()) {
                log.error("解压玩家阵容出现错误 {}", psA.getUid());
                return r.fail();
            }
            sideA = uncompressEc.data;
        }
        if (Objects.nonNull(psB)) {
            record.setPsB(psB.getCpsList().size() - 1);
            CompressedContent last = psB.getCpsList().getLast();
            EcResult<PlaySide> uncompressEc = PlaySideCompressHelper.uncompressEc(last);
            if (!uncompressEc.ok()) {
                log.error("解压玩家阵容出现错误 {}", psB.getUid());
                return r.fail();
            }
            sideB = uncompressEc.data;
        }
        if (Objects.isNull(sideA) || Objects.isNull(sideB)) {
            byte winner = Objects.nonNull(sideA) ? GDFight.Team.A : GDFight.Team.B;
            record.setWinner(winner);
            long powerA = Objects.nonNull(sideA) ? sideA.getTotalPower() : 0L;
            long powerB = Objects.nonNull(sideB) ? sideB.getTotalPower() : 0L;
            r.data = Math.abs(powerA - powerB);
            handleResult(record, psA, psB, winner, !ChampionRaceSpecUtils.isTrial(record.getSpec()));
            return r.success();
        }

        GameResult<PlayPO> pr = startFight(sideA, sideB);
        if (!pr.ok()) {
            log.error("战斗出现错误!");
            return r.fail();
        }
        PlayPO play = pr.data;
        play.story.level = ChampionRaceSpecUtils.getVideoLevel(record.getSpec());
        record.setWinner(play.winner);
        record.setRecordTime(play.startTime);
        handleResult(record, psA, psB, play.winner, !ChampionRaceSpecUtils.isTrial(record.getSpec()));
        upsertVideoRecord(record, play);
        r.data = Math.abs(sideA.getTotalPower() - sideB.getTotalPower());
        return r.success();
    }

    private void handleResult(ChampionRaceRecord record, ChampionRacePs psA, ChampionRacePs psB, byte winner, boolean count) {
        if (winner == GDFight.Team.A) {
            record.setAPoints(psA.getOpponent().getPoints());
            psA.getOpponent().win(count, parent.getTableFacade().championRace.round.getPoints(ChampionRaceSpecUtils.getVideoLevel(record.getSpec())));
            record.setAPointsChanged(psA.getOpponent().getPoints() - record.getAPoints());
            if (Objects.nonNull(psB)) {
                record.setBPoints(psB.getOpponent().getPoints());
                psB.getOpponent().lose(count);
                record.setBPointsChanged(psB.getOpponent().getPoints() - record.getBPoints());
            }
        } else if (!ChampionRaceSpecUtils.isTrial(record.getSpec())) {
            record.setBPoints(psB.getOpponent().getPoints());
            psB.getOpponent().win(count, parent.getTableFacade().championRace.round.getPoints(ChampionRaceSpecUtils.getVideoLevel(record.getSpec())));
            record.setBPointsChanged(psB.getOpponent().getPoints() - record.getBPoints());
            if (Objects.nonNull(psA)) {
                record.setAPoints(psA.getOpponent().getPoints());
                psA.getOpponent().lose(count);
                record.setAPointsChanged(psA.getOpponent().getPoints() - record.getAPoints());
            }
        }
    }

    private GameResult<PlayPO> startFight(PlaySide psA, PlaySide psB) {
        FightSide fsA = FightSide.build(parent.getPlayBuildContext(), GDFight.Team.A, psA);
        FightSide fsB = FightSide.build(parent.getPlayBuildContext(), GDFight.Team.B, psB);
        return parent.getFightHandler().start(new ChampionRaceFTC(), fsA, fsB);
    }

    public void upsertVideoRecord(ChampionRaceRecord record, PlayPO play) {
        parent.upsertVideo(record.getSpec(), ChampionRaceVideo.of(play.uid, record.getSpec(), play, true));
        try {
            ReplaySaveReq saveReq = ReplayUtils.toReplaySaveReq(new PlayVO().read(play), System.currentTimeMillis() + GDChampionRace.WHOLE_SEASON_TIME);
            context.api.openApi().saveReplay(saveReq,
                    er -> {
                        log.info("openApi之保存录像(异步)的结果是{}, ID {}", er, er.data.getId());
                        record.setReplayId2(er.data.getId());
                    }
            );
        } catch (Exception e) {
            log.error("保存REPLAY发生错误", e);
        }
    }
}
